
package com.hlkj.pay.app.merchant.ext.impl.icbcpay.ext;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.framework.extension.annotation.Extension;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelPayOrderQueryContext;
import com.hlkj.pay.app.merchant.ext.dto.order.ChannelRefundPayOrderContext;
import com.hlkj.pay.app.merchant.ext.impl.icbcpay.IcbcPayScenePayOrderExtPt;
import com.hlkj.pay.app.merchant.ext.impl.icbcpay.constant.IcbcPayConstant;
import com.hlkj.pay.app.merchant.ext.impl.icbcpay.constant.IcbcPayExtConstant;
import com.hlkj.pay.app.merchant.ext.impl.icbcpay.dto.IcbcPayConfig;
import com.hlkj.pay.app.merchant.ext.impl.icbcpay.dto.req.OrderCreateReq;
import com.hlkj.pay.app.merchant.ext.impl.icbcpay.dto.rsp.OrdeCreateDataRsp;
import com.hlkj.pay.app.merchant.ext.impl.icbcpay.utils.HttpUtils;
import com.hlkj.pay.app.merchant.ext.impl.icbcpay.utils.IcbcPaySignUtil;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.infrastructure.model.order.PayOrderDO;
import com.hlkj.pay.infrastructure.model.pay.PayWayDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.util.DateUtils;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.vo.order.req.PayOrderCommonParamReq;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 主扫统一下单 用户扫支付码
 *
 * @author HlpayTeam
 * @date 2024/11/18 13:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
@Extension(bizId = IcbcPayExtConstant.PAY)
public class IcbcPayScanPayOrderExtPt extends IcbcPaySceneCommonPayOrder implements IcbcPayScenePayOrderExtPt {

    @Override
    public void submitChannelPayOrder(ChannelPayOrderContext channelPayOrderContext) {
//        ALIPAY	JSAPI，H5
//        WXPAY	JSAPI, MINI_PROGRAM, H5
        // 配置转换
        ProviderChannelConfigDO providerChannelConfigDO = channelPayOrderContext.getProviderChannelConfigDO();
        String channelConfig = providerChannelConfigDO.getParamsConfig();
        IcbcPayConfig payConfig = getPayConfig(channelConfig, channelPayOrderContext.getMerchantAppChannelDO());
        PayOrderDO payOrderDO = channelPayOrderContext.getPayOrderDO();
        try {
            PayWayDO payWayDO = channelPayOrderContext.getPayWayDO();
            OrderCreateReq bodyReq = new OrderCreateReq();
            bodyReq.setPartnerNo(payConfig.getPartnerNo());
            bodyReq.setMerchantNo(payConfig.getMerchantNo());
            bodyReq.setTransDate(DateUtils.getCurrentTime().toString());
            bodyReq.setTransNonce(payOrderDO.getPayOrderNo());
            bodyReq.setOutTradeNo(payOrderDO.getPayOrderNo());
            bodyReq.setTradeAmount(MerchantUtils.YuanToFen(payOrderDO.getAmount()));
            String payType = getPayType(payWayDO);
            String paySubType = getPaySubType(payWayDO);
            bodyReq.setPayBrand(payType);
            bodyReq.setNotifyUrl(channelPayOrderContext.getNotifyUrl());
            bodyReq.setPayWayType(paySubType);
            bodyReq.setTradeSubject(payOrderDO.getSubject());
            bodyReq.setScanType("USM");
            bodyReq.setRequestIp(payOrderDO.getClientIp());
            bodyReq.setPsType("N");
            if ("WXPAY".equals(payType) || ("ALIPAY".equals(payType) && !"NATIVE".equals(paySubType))) {
                Map<String, Object> wxBizParam = new HashMap<>();
                if (!StringUtils.hasText(payOrderDO.getExtra())) {
                    log.error("工行聚合下单请求失败 message:{}", "通道额外参数不能为空");
                    channelPayOrderContext.setRemark("工行聚合下单请求失败, 通道额外参数不能为空");
                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                    return;
                }
                PayOrderCommonParamReq.Extra extra = channelPayOrderContext.getExtra();
//                PayOrderCommonParamReq.Extra extra = JsonUtils.parseObject(payOrderDO.getExtra(), PayOrderCommonParamReq.Extra.class);
                if (!StringUtils.hasText(extra.getSubAppid())) {
                    channelPayOrderContext.setRemark("下单请求失败, APPID不能为空");
                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                    return;
                }
                if (!StringUtils.hasText(extra.getUserId())) {
                    channelPayOrderContext.setRemark("下单请求失败, 用户标识不能为空");
                    channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                    return;
                }
                if ("WXPAY".equals(payType)) {
                    wxBizParam.put("wxAppId", extra.getSubAppid());
                    wxBizParam.put("wxOpenId", extra.getUserId());
                } else {
                    wxBizParam.put("alipayAppId", extra.getSubAppid());
                    wxBizParam.put("alipayUnionId", extra.getUserId());
                }
                wxBizParam.put("jumpUrl", channelPayOrderContext.getRedirectUrl());
                bodyReq.setExtendInfo(JsonUtils.toJsonString(wxBizParam));
            }

            String url = domain(channelPayOrderContext.isTest()) + IcbcPayConstant.TRADE_CREATE;
            bodyReq.setSignature(IcbcPaySignUtil.sign(bodyReq, payConfig.getMchPrivateKey()));
            log.info("工行支付下单req参数:{}", bodyReq);
            String response = HttpUtils.post(url, bodyReq);
            log.info("工行支付下单返回参数:{}", response);

            OrdeCreateDataRsp rspBody = JsonUtils.parseObject(response, OrdeCreateDataRsp.class);
            if ("00000000".equals(rspBody.getCode())) {
                log.info("工行支付下单返回消息体:{}", rspBody);
                channelPayOrderContext.setPayDataType("form");
                channelPayOrderContext.setInsOrderNo(rspBody.getTradeNo());
                channelPayOrderContext.setPayInfo(rspBody.getFormInput());
            } else {
                String respDesc = rspBody.getMessage();
                channelPayOrderContext.setProcessStatus(Boolean.FALSE);
                if (StringUtils.hasText(respDesc)) {
                    channelPayOrderContext.setRemark(respDesc);
                } else {
                    channelPayOrderContext.setRemark("工行支付下单查询返回错误信息为空,错误码为:" + rspBody.getCode());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("工行支付下单请求失败 message:{}", e.getMessage(), e);
            channelPayOrderContext.setRemark("工行支付下单请求失败,失败信息" + e.getMessage());
            channelPayOrderContext.setProcessStatus(Boolean.FALSE);
        }
    }

    private String getPayType(PayWayDO payWayDO) {
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        if (Objects.isNull(payType)) return "";
        switch (payType) {
            case WECHAT:
                return "WXPAY";
            case ALIPAY:
                return "ALIPAY";
        }
        return "";
    }

    private String getPaySubType(PayWayDO payWayDO) {
        PayEnums.SCENE_PAY_TYPE scenePayType = PayEnums.SCENE_PAY_TYPE.from(payWayDO.getSubType());
        PayEnums.PAY_TYPE payType = PayEnums.PAY_TYPE.fromByCode(payWayDO.getType());
        if (Objects.isNull(scenePayType) || Objects.isNull(payType)) return "";
        switch (scenePayType) {
            case APP:
            case H5:
                return "H5";
            case MINI_APP:
                return "MINI_PROGRAM";
            case JSAPI:
                return "JSAPI";
            case QR:
                switch (payType) {
                    case WECHAT:
                        return "JSAPI";
                    case ALIPAY:
                        return "NATIVE";
                }
        }
        return "";
    }

    @Override
    public void queryChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void closeChannelPayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonCloseChannelPayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void queryChannelClosePayOrder(ChannelPayOrderQueryContext channelPayOrderQueryContext) {
        commonQueryChannelClosePayOrder(channelPayOrderQueryContext);
    }

    @Override
    public void refundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public void queryRefundChannelPayOrder(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        commonQueryRefundChannelPayOrder(channelRefundPayOrderContext);
    }

    @Override
    public boolean refundApply(ChannelRefundPayOrderContext channelRefundPayOrderContext) {
        return true;
    }

    @Override
    public CommonResult<String> channelOrderCode(ChannelPayOrderContext channelPayOrderContext) {
        return CommonResult.success();
    }

}
